package com.fuyc.project.tools.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import ch.ethz.ssh2.ChannelCondition;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import lombok.extern.slf4j.Slf4j;

/**
 * 用于远程执行ssh命令
 */
@Slf4j
public class RemoteSSHUtils {
	
	public final static String S_stdioOut="S_STDIO_OUT";
	
	public final static String S_stdioErr="S_STDIO_ERR";
	
	public final static String S_Status="STATUS";
	
	public final static String S_exitSignal="EXIT_SIGNAL";
		
	public static String S_encoding = Charset.defaultCharset().toString();
	
	/**
	 * 将本地的文件拷贝到远程主机目录
	 * 注意：必须是linux主机；路径必须是全路径
	 * # 参数1：用户名
# 参数2：密码
# 参数3：远程ip
# 参数4：本地目录
# 参数5：远程目录
	 * */
	public static void scpFileLocal2Remote(String ip,String userName,String passWord,long timeOut,String localAbsFilePath,String remoteAbsFilePath) {
		
	}
	
	/**
	 * 远程命令调用，判定结果是否符合预期(忽略大小写)
	 * @param ip 远程主机ip
	 * @param userName 远程主机用户名
	 * @param passWord 远程追加密码
	 * @param command 待执行命令
	 * @param expectList  期望包含的结果
	 * @param unExpectList 不期望包含的结果
	 * 
	 * @return 
	 * 		false :不符合预期
	 * 		true :符合预期
	 * */
	public static boolean isCommandExpected(String ip,String userName,String passWord,String command,long timeOut,List<String> expectList,List<String> unExpectList) {
		try {
			String stdo=getExeCommandStr(ip, userName, passWord, command, timeOut);
			if(stdo==null) {
				throw new Exception("未获取到有效的输出！请重新操作或者查看没有输出原因！");
			}
			//先判断不符合预期的
			if(unExpectList!=null && unExpectList.size()>0) {
				for(String temp:unExpectList) {
					if(StringUtils.containsIgnoreCase(stdo, temp)) {
						return false;
					}
				}
			}
			
			if(expectList!=null && expectList.size()>0) {
				for(String temp:expectList) {
					if(!StringUtils.containsIgnoreCase(stdo, temp)) {
						return false;
					}
				}
			}
			
			return true;
		} catch (Exception e) {
			log.error(e+"");
		}
		return false;
		
	}
	
	/**
	 * 远程执行ssh命令，执行完连接关闭，不允许大批量使用
	 * @param ip 远程地址
	 * @param userName 远程用户名
	 * @param passWord 远程密码
	 * @param commend 待执行的命令，如果是多条命令，命令之间使用分号分割
	 * @param timeOut 超时时间，如果不传，默认是5分钟
	 * @return 执行命令的输出，如果出错返回null
	 * @throws Exception 
	 */
	public static String getExeCommandStr(String ip,String userName,String passWord,String command,long timeOut) throws Exception {
		Map<String,String> resMap = exeCommand(ip, userName, passWord, command, timeOut);
		if(resMap==null) {
			return null;
		}
		return resMap.get(S_stdioOut);
	}
	
	
	/**
	 * 远程执行ssh命令，执行完连接关闭，不允许大批量使用
	 * @param ip 远程地址
	 * @param userName 远程用户名
	 * @param passWord 远程密码
	 * @param command 待执行的命令，如果是多条命令，命令之间使用分号分割
	 * @param timeOut 超时时间，如果不传，默认是5分钟
	 * @return Map<String,String> 返回的结果信息，具体键参看本工具类定义的常量
	 * @throws Exception 
	 */
	public static Map<String,String> exeCommand(String ip,String userName,String passWord,String command,long timeOut) throws Exception {
		if(StringUtils.isBlank(command)) {
			throw new Exception("待执行的命令为空，请输入正确的待执行命令");
		}
		if(StringUtils.isBlank(ip)) {
			throw new Exception("输入的地址为空，请输入正确的远程地址");
		}
		if(StringUtils.isBlank(userName)) {
			throw new Exception("输入的用户名为空，请输入正确的用户名");
		}
		if(timeOut<0) {
			timeOut=1000 * 5 * 60;
		}
		Session session=null;
		Connection conn=null;
		Map<String,String> resultMap=null;
		try {
			conn=getConnection(ip, userName, passWord);
			if(conn==null) {
				log.error("执行shell，获取连接失败！请检查用户名，密码");
				return null;
			}
			session=conn.openSession();
			if(session==null) {
				log.error("执行shell,未获取到有效session");
				return null;
			}
			session.execCommand(command);
			String stdioStr=stream2String(new StreamGobbler(session.getStdout()));
			String stdioErr=stream2String(new StreamGobbler(session.getStderr()));
			session.waitForCondition(ChannelCondition.EXIT_STATUS, timeOut);
			String exitSignl=session.getExitSignal();
			String state=session.getState()+"";
			resultMap=new HashMap<String,String>();
			resultMap.put(S_Status, state);
			resultMap.put(S_exitSignal, exitSignl);
			resultMap.put(S_stdioErr, stdioErr);
			resultMap.put(S_stdioOut, stdioStr);
		}catch(Exception e){
			log.error(e.toString());
			throw e;
		}finally {
			if(session!=null) {
				session.close();
			}
			if(conn!=null) {
				conn.close();
			}
		}
		return resultMap;
	}

	/**
	 * 不推荐其他方法调用，原本是private,为了编译单独放开，请不要随意调用
	 * */
	public static String stream2String(InputStream in) throws Exception {
		StringBuffer sb=new StringBuffer();
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(in,S_encoding));
			while (true) {
				String line = br.readLine();
				if (line == null) {
					break;
				}
				sb.append(line).append("\r");
			}
		} finally {
			if(in!=null) {
				in.close();
			}
		}
		return sb.toString();
	}
	
	/**
	 * 获取远程主机连接
	 * */
	private static  Connection getConnection(String ip,String userName,String passWord){
		Connection conn =null;
		boolean isSuccess=false;
		try {
			conn = new Connection(ip);
			conn.connect(); // 连接
			isSuccess=conn.authenticateWithPassword(userName, passWord); // 认证
			if(isSuccess) {
				return conn;
			}
		} catch (Exception e) {
			log.error("远程连接失败："+e);
			isSuccess=false;
		}finally {
			if(!isSuccess&&conn!=null) {
				conn.close();		
			}
		}	
		return null;
	}
	
	
	
}
